package com.tbocek.android.ode.controller;
import java.util.List;

import com.google.common.collect.Lists;
import com.tbocek.android.ode.solver.Solver;
import com.tbocek.android.ode.solver.SystemState;


public class Controller {
	
	private List<ODEControllerListener> mListeners = Lists.newArrayList();
	
	/**
	 * The computation currently being performed.
	 */
	private List<ComputationSpec> mCurrentComputation;
	
	/**
	 * The computation to perform after the current computation completes.
	 */
	private List<ComputationSpec> mPendingComputation;
	
	/**
	 * Asynchronous computation task.
	 */
	private ComputationTask mComputationTask = new ComputationTask(this);
	
	public interface ODEControllerListener {
		void onSolution(List<SystemState> solution);
		void onSweep(List<List<SystemState>> sweep);
	}
	
	public void requestSolve(
			System system, Solver solver, SystemState initialState, 
			float finalTime) {
		
	}
	
	public void requestSweep(
			System system, Solver solver, List<SystemState> initialStates, 
			float finalTime) {
		
	}
	
	public void requestSweep(
			List<System> system, Solver solver, SystemState initialState, 
			float finalTime) {
		
	}
	
	public void notifySolution(List<SystemState> solution) {
		for (ODEControllerListener listener: mListeners) {
			listener.onSolution(solution);
		}
	}
	
	public void notifySweep(List<List<SystemState>> sweep) {
		for (ODEControllerListener listener: mListeners) {
			listener.onSweep(sweep);
		}
	}
	
	/**
	 * Either begins the given computation, or updates the pending computation
	 * such that the given computation will execute once the current computation
	 * finishes. Unless, of course, a more recent computation pre-empts it.
	 * @param task The computational task to begin.
	 */
	@SuppressWarnings("unchecked")
	private void beginComputation(List<ComputationSpec> task) {
		if (mCurrentComputation == null) {
			mCurrentComputation = task;
			mComputationTask.execute(task);
		} else {
			mPendingComputation = task;
		}
	}
	
	/**
	 * Marks the current computation as ended, and begins any pending
	 * computations.
	 */
	@SuppressWarnings("unchecked")
	public void endCurrentComputation() {
		mCurrentComputation = null;
		if (mPendingComputation != null) {
			mCurrentComputation = mPendingComputation;
			mPendingComputation = null;
			mComputationTask.execute(mCurrentComputation);
		}
	}
}
